from machine import SPI,Pin
import framebuf
import time
import math
from ufont import BMFont

def color(r, g, b):
    i = (((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3)).to_bytes(2, "little")
    return (i[0] << 8) + i[1]

font = BMFont("font.bmf")

class ST7735(framebuf.FrameBuffer):
    def __init__(self, width, height, spi, dc, cs, rst=None,bl=None, rotate=0):
        self.width = width
        self.height = height
        self.rotate = rotate
        self.spi = spi
        self.dc = dc
        self.cs = cs
        self.rst = rst
        self.bl = bl
       
        if self.rst is not None:
            self.rst.init(Pin.OUT, value=1)

        self.cs.init(Pin.OUT, value=1)
        self.dc.init(Pin.OUT, value=0)
        if  self.bl is not None:
            self.bl.init(Pin.OUT, value=0)
        
        self._init()
        self.buffer = bytearray(self.width * self.height * 2)
        super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
        self.fill(0)
        self.show()

    def _write(self, command, data=None):
        self.cs(0)
        self.dc(0)
        self.spi.write(bytearray([command]))
        if data is not None:
            self.dc(1)
            self.spi.write(data)
        self.cs(1)
    def _reset(self):
        if self.rst is not None:
            self.rst(0)
            time.sleep_ms(100)
            self.rst(1)
            time.sleep_ms(100)
        
    def _init(self):
        self._reset()
        init_commands = [
            (0x01, None),                 # Software reset
            (0x11, None),                 # Sleep exit
            (0xB1, b'\x01\x2C\x2D'),      # Frame Rate Control (normal mode)
            (0xB2, b'\x01\x2C\x2D'),      # Frame Rate Control (idle mode)
            (0xB3, b'\x01\x2C\x2D\x01\x2C\x2D'), # Frame Rate Control (partial mode)
            (0xB4, b'\x07'),              # Display Inversion Control
            (0xC0, b'\xA2\x02\x84'),     # Power Control 1
            (0xC1, b'\xC5'),              # Power Control 2
            (0xC2, b'\x0A\x00'),          # Power Control 3
            (0xC3, b'\x8A\x2A'),          # Power Control 4
            (0xC4, b'\x8A\xEE'),          # Power Control 5
            (0xC5, b'\x0E'),              # VCOM Control 1
            (0x20, None),                 # Display Inversion Off
            (0x36, b'\xC8' if self.rotate == 0 else b'\x08'), # MADCTL
            (0x3A, b'\x05'),             # Color Mode (16-bit)
            (0x29, None),                # Display On
        ]
        
        for cmd, data in init_commands:
            self._write(cmd, data)
            time.sleep_ms(10)
            
    def back_light(self, value):
        bl(value)
    

    def circle(self, center, radius, c=color(255, 255, 255), section=100):
        """
        画圆
        :param c: 颜色
        :param center: 中心(x, y)
        :param radius: 半径
        :param section: 分段
        :return:
        """
        arr = []
        for m in range(section + 1):
            x = round(radius * math.cos((2 * math.pi / section) * m - math.pi) + center[0])
            y = round(radius * math.sin((2 * math.pi / section) * m - math.pi) + center[1])
            arr.append([x, y])
        for i in range(len(arr) - 1):
            self.line(*arr[i], *arr[i + 1], c)
#        print(hex(c))
 
    def clear(self):
        self.fill(0)
        self.show()
        if self.bl is not None:
            self.bl(0)
 
    def image(self, file_name):
        with open(file_name, "rb") as bmp:
            for b in range(0, 80 * 160 * 2, 1024):
                self.buffer[b:b + 1024] = bmp.read(1024)
            self.show()
            
    def showstring(self,string,x = 0, y = 0, c=color(0xA0,0xA0,0xA),font_size=16,reverse = False,clear = False,show = True,half_char = True,auto_wrap = True):
            font.text(self,string ,x,y,c,font_size,reverse ,clear,show,half_char,auto_wrap)   

        
    def show(self):
        if self.bl is not None:
            self.bl(1)
        self._write(0x2A, b'\x00\x00\x00\x7F')  # Column address set
        self._write(0x2B, b'\x00\x00\x00\x9F')  # Row address set
        self._write(0x2C, self.buffer)          # Memory write